package risk.control.project.framework.service;

import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisPool;
import risk.control.project.config.constant.SecretKey;
import risk.control.project.framework.base.BaseEncryption;
import risk.control.project.framework.entity.TokenBean;
import risk.control.project.utils.UUIDUtils;
import risk.control.project.utils.aes.CBC_Encryption;

import java.util.HashMap;

/**
 * token服务类
 */
@Service
public class TokenService extends BaseEncryption {

    private static final Logger logger = LoggerFactory.getLogger(TokenService.class);

    private static final String secretKey = SecretKey.Map.get("token_secret_key");

    @Qualifier("JedisPool")
    private final JedisPool jedisPool;

    public TokenService(JedisPool jedisPool) {
        this.jedisPool = jedisPool;
    }

    /**
     * 通过userId生成token
     *
     * @param userId userId
     * @return token
     */
    public String generateToken(String userId) {
        if (userId == null || userId.isEmpty()) {
            return "";
        }
        TokenBean tokenBean = new TokenBean();
        tokenBean.tokenTime = String.valueOf(System.currentTimeMillis());//token生成时间
        tokenBean.userId = userId;//用户id
        tokenBean.unique = UUIDUtils.generate();//唯一标识
        String jsonString = JSON.toJSONString(tokenBean);//bean->json
        String token = CBC_Encryption.encrypt(secretKey, jsonString);//加密
        //保存至redis,默认有效期是24小时(单位：秒)
        long survivalTime = 60 * 60 * 24;
        try (Jedis jedis = jedisPool.getResource()) {
            jedis.setex(generateTokenKey(userId), survivalTime, token);
        }
        return token;
    }

    /**
     * 根据请求体，校验token的合法性
     *
     * @param realBody realBody
     * @return resMap
     */
    public HashMap<String, String> verifier(String realBody) {
        HashMap<String, String> resMap = new HashMap<>();
        if (realBody == null || realBody.isEmpty()) {
            resMap.put("state", "001");
            resMap.put("msg", "body为空");
            return resMap;
        }
        JSONObject jsonObject = (JSONObject) JSON.parse(realBody);
        String token = jsonObject.getString("token");
        if (token == null || token.isEmpty()) {
            resMap.put("state", "002");
            resMap.put("msg", "token为空");
            return resMap;
        }
        TokenBean tokenBean = decryptToken(token);
        String userId = tokenBean.userId;
        if (userId == null || userId.isEmpty()) {
            resMap.put("state", "003");
            resMap.put("msg", "token解析失败");
            return resMap;
        }
        String latestToken = getTokenForUserId(userId);//获取保存在redis中的token
        //说明token失效
        if (latestToken == null || latestToken.isEmpty()) {
            //被其他设备登录了，不是最新的token
            resMap.put("state", "004");
            resMap.put("msg", "token已经失效，请从新登录");
            return resMap;
        }
        //说明token还没失效->判断当前token和latestToken是否一致
        if (!latestToken.equals(token)) {
            //被其他设备登录了，不是最新的token
            resMap.put("state", "005");
            resMap.put("msg", "当前账号已在其他设备登录，请从新登录，并注意账号安全");
            return resMap;
        }
        resMap.put("state", "000");
        resMap.put("msg", "验证通过");
        return resMap;
    }

    /**
     * 根据userId从redis获取token
     *
     * @param userId userId
     * @return token
     */
    public String getTokenForUserId(String userId) {
        try (Jedis jedis = jedisPool.getResource()) {
            String tokenKey = generateTokenKey(userId);
            boolean exists = jedis.exists(tokenKey);
            if (!exists) {
                //不存在，说明过期了
                return "";
            }
            return jedis.get(tokenKey);
        }
    }

    /**
     * 加密和解析token
     *
     * @param token token
     * @return 真实token->json格式
     */
    public TokenBean decryptToken(String token) {
        if (token != null && !token.isEmpty()) {
            String tokenJson = CBC_Encryption.decrypt(secretKey, token);
            return JSONObject.parseObject(tokenJson, TokenBean.class);
        } else {
            return new TokenBean();
        }
    }


    public void clearTokenForUserid(String userId) {
        try (Jedis jedis = jedisPool.getResource()) {
            String tokenKey = generateTokenKey(userId);
            boolean exists = jedis.exists(tokenKey);
            if (exists) {
                //存在
                jedis.del(tokenKey);
            }
        }
    }

    /**
     * 根据userId生成统一格式的tokenKey，方便从redis拿取操作
     *
     * @param userId userId
     * @return TokenKey
     */
    private String generateTokenKey(String userId) {
        return "token_key_" + userId;
    }
}
